package person.zjh.kaoyansharehub.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.UUID;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import person.zjh.kaoyansharehub.config.UploadFileConfig;
import person.zjh.kaoyansharehub.dto.MaterialSaveDTO;
import person.zjh.kaoyansharehub.dto.PageMaterialDTO;
import person.zjh.kaoyansharehub.mapper.DownloadLogMapper;
import person.zjh.kaoyansharehub.mapper.ImgCoverMapper;
import person.zjh.kaoyansharehub.mapper.ImgPreviewMapper;
import person.zjh.kaoyansharehub.mapper.MaterialMapper;
import person.zjh.kaoyansharehub.pojo.DownloadLog;
import person.zjh.kaoyansharehub.pojo.ImgCover;
import person.zjh.kaoyansharehub.pojo.ImgPreview;
import person.zjh.kaoyansharehub.pojo.Material;
import person.zjh.kaoyansharehub.result.PageResult;
import person.zjh.kaoyansharehub.result.Result;
import person.zjh.kaoyansharehub.service.MaterialService;
import person.zjh.kaoyansharehub.vo.MaterialVO;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.List;

import static person.zjh.kaoyansharehub.config.UploadFileConfig.UPLOAD_FILE_SAVE_PATH;

/**
 * @description: 学习资料接口实现层
 * @author 郑佳豪
 * @date 2025/2/13 16:25
 * @version 1.0
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class MaterialServiceImpl extends ServiceImpl<MaterialMapper,Material> implements MaterialService {

    private final ImgCoverMapper imgCoverMapper;

    private final MaterialMapper materialMapper;

    private final ImgPreviewMapper imgPreviewMapper;

    private final DownloadLogMapper downloadLogMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> saveMaterial(MaterialSaveDTO requestParam) {

        MultipartFile materialMaterials = requestParam.getMaterialMaterials();
        String fileType = materialMaterials.getOriginalFilename().substring(materialMaterials.getOriginalFilename().lastIndexOf("."));
        try {
            String filePath = saveMaterial(materialMaterials); //获得资料上传后的路径
            Material material = Material.builder()
                    .filePath(filePath) //文件路径
                    .fileType(fileType) //文件类型
                    .categoryId(requestParam.getCategoryId()) //种类id
                    .title(requestParam.getMaterialName()) //标题
                    .description(requestParam.getMaterialDescription()) //描述
                    .userId(requestParam.getUploaderId()) //上传者id
                    .year(requestParam.getYear()) //年份
                    .build();
            log.info("资料信息{}", material);
            materialMapper.insert(material);
            log.info("资料信息{}", material);

            Long materialId = material.getMaterialId(); //获取插入后的资料id

            String imgCoverFilePath = saveMaterial(requestParam.getMaterialCover()); //获取封面图片数据
            ImgCover imgCover = ImgCover.builder()
                    .materialId(materialId) //资料id
                    .imgPath(imgCoverFilePath) //资料图片
                    .build();
            imgCoverMapper.insert(imgCover);


            List<MultipartFile> materialPreviews = requestParam.getMaterialPreviews(); //获得预览图片集合
            for (MultipartFile materialPreview : materialPreviews) { //遍历集合
                String imgPreviewFilePath = saveMaterial(materialPreview); //保存到本地
                ImgPreview imgPreview = ImgPreview.builder() //创建实体类
                        .materialId(materialId)
                        .imgPath(imgPreviewFilePath)
                        .build();
                imgPreviewMapper.insert(imgPreview); //插入记录
            }
            log.info("文件上传成功");

            return Result.success();
        } catch (Exception e) {
            log.error("文件上传失败");
            e.printStackTrace();
            return Result.error("文件上传失败");
        }

    }

    @Override
    public PageResult pageMaterial(PageMaterialDTO requestParam) {

        PageHelper.startPage(requestParam.getPageNum(), requestParam.getPageSize());
        List<MaterialVO> materialVOList = materialMapper.queryMaterial(requestParam);
        PageInfo<MaterialVO> pageInfo = new PageInfo<>(materialVOList);
        return new PageResult(pageInfo.getTotal(), pageInfo.getList());
    }

    @Override
    public MaterialVO queryMaterial(Long materialId) {
        Material material = materialMapper.selectById(materialId);
        MaterialVO materialVO = BeanUtil.copyProperties(material, MaterialVO.class);

        LambdaQueryWrapper<ImgPreview> eq = new LambdaQueryWrapper<ImgPreview>()
                .eq(ImgPreview::getMaterialId, materialId);
        List<ImgPreview> imgPreviews = imgPreviewMapper.selectList(eq);
        materialVO.setImgPreviewList(imgPreviews);
        LambdaQueryWrapper<ImgCover> wrapper = new LambdaQueryWrapper<ImgCover>()
                .eq(ImgCover::getMaterialId, materialId);
        ImgCover imgCover = imgCoverMapper.selectOne(wrapper);
        materialVO.setImgPath(imgCover.getImgPath());
        return materialVO;
    }

    @Override
    public List<MaterialVO> getNewMaterialList(Long categoryId) {
        LambdaQueryWrapper<Material> queryWrapper = new LambdaQueryWrapper<Material>()
                .eq(categoryId != null,Material::getCategoryId,categoryId)
                .orderByDesc(Material::getCreatedAt);
        queryWrapper.last("LIMIT 10");
        List<Material> materialList = materialMapper.selectList(queryWrapper);
        List<MaterialVO> materialVOS = BeanUtil.copyToList(materialList, MaterialVO.class);
        for (MaterialVO materialVO : materialVOS) {
            LambdaQueryWrapper<ImgCover> wrapper = new LambdaQueryWrapper<ImgCover>()
                    .eq(ImgCover::getMaterialId, materialVO.getMaterialId());
            ImgCover imgCover = imgCoverMapper.selectOne(wrapper);
            materialVO.setImgPath(imgCover.getImgPath());
        }
        return materialVOS;
    }

    @Override
    public PageResult getUserPublishArticle(PageMaterialDTO requestParam) {

        PageHelper.startPage(requestParam.getPageNum(),requestParam.getPageSize());
        LambdaQueryWrapper<Material> queryWrapper = new LambdaQueryWrapper<Material>()
                .eq(Material::getUserId,requestParam.getUserId())
                .orderByDesc(Material::getCreatedAt);
        List<Material> materialList = materialMapper.selectList(queryWrapper);
        log.info("数据集合:{}",materialList);
        PageInfo<Material> pageInfo = new PageInfo<>(materialList);
        List<MaterialVO> materialVOS = BeanUtil.copyToList(materialList, MaterialVO.class);
        for (MaterialVO materialVO : materialVOS) {
            LambdaQueryWrapper<ImgCover> wrapper = new LambdaQueryWrapper<ImgCover>()
                    .eq(ImgCover::getMaterialId, materialVO.getMaterialId());
            ImgCover imgCover = imgCoverMapper.selectOne(wrapper);
            materialVO.setImgPath(imgCover.getImgPath());
        }
        return new PageResult(pageInfo.getTotal(),materialVOS);

    }

    @Override
    public Result downloadFile(HttpServletRequest request, HttpServletResponse response,String filePath, Long materialId, Long userId) {

        // 清空输出流
        response.reset();
        File file = new File(UploadFileConfig.UPLOAD_FILE_SAVE_PATH + filePath);
        // 获取文件名
        String fileName = file.getName();
        try {
            // 对文件名进行编码 防止乱码
            String encodedFileName = URLEncoder.encode(fileName, "UTF-8");

            // 根据不同浏览器设置 Content-Disposition 响应头
            String userAgent = request.getHeader("User-Agent");
            String contentDisposition;
            if (userAgent != null && userAgent.contains("MSIE") || userAgent.contains("Trident")) {
                // 针对 IE 浏览器
                contentDisposition = "attachment;filename=" + encodedFileName;
            } else {
                // 针对其他浏览器
                contentDisposition = "attachment;filename*=UTF-8''" + encodedFileName;
            }

            response.setHeader("Content-Disposition", contentDisposition);
            // 设置响应内容类型
            response.setContentType("application/octet-stream");
            InputStream fileInputStream = new FileInputStream(file);
            ServletOutputStream outputStream = response.getOutputStream();
            IOUtils.copy(fileInputStream, outputStream);
            outputStream.flush();
            fileInputStream.close();
            outputStream.close();
            LambdaUpdateWrapper<Material> updateWrapper = new LambdaUpdateWrapper<Material>()
                    .eq(Material::getMaterialId, materialId)
                    .setSql("download_count = download_count + 1");
            materialMapper.update(updateWrapper);

            DownloadLog downloadLog = DownloadLog.builder()
                    .userId(userId)
                    .materialId(materialId).build();
            downloadLogMapper.insert(downloadLog);

            return Result.success();
        } catch (IOException e) {
            log.info("下载文件失败");
            e.printStackTrace();
            return Result.error("下载文件失败");
        }
    }

    @Override
    public Result getUserPublishMaterialCount(Long userId) {

        LambdaQueryWrapper<Material> wrapper = new LambdaQueryWrapper<Material>()
                .eq(Material::getUserId, userId);
        long count = count(wrapper);
        return Result.success(count);

    }

    /**
     * 保存资料数据
     * @param multipartFile 文件
     */
    public String saveMaterial(MultipartFile multipartFile) throws Exception {
        String originalFilename = multipartFile.getOriginalFilename();
        String uniqueFileName = UUID.randomUUID() + "_" + originalFilename;

        String filePath = UPLOAD_FILE_SAVE_PATH + uniqueFileName;
        File dest = new File(filePath);
        // 确保目录存在
        if (!dest.getParentFile().exists()) {
            if (!dest.getParentFile().mkdirs()) {
                log.error("无法创建目录: {}", dest.getParentFile().getAbsolutePath());
            }
        }
        log.info("文件路径:{}", filePath);
        log.info("文件相对路径:{}", dest.getPath());
        // 保存文件
        multipartFile.transferTo(dest);
        return uniqueFileName;
    }

}
